package org.example.thread3;

import java.util.Date;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 通过共享对象来实现线程间数据共享
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2020/10/31 16:27
 */
public class ThreadByThread extends Thread {
    /**
     * 共享对象，初始化传参
     */
    private User user;

    public ThreadByThread(User user) {
        this.user = user;
    }

    @Override
    public void run() {
        /**
         * 这里如果不做线程同步，就会涉及到Java内存模型中脏读的问题，导致某些线程工作内容中的数据与-
         * 主内存中的数据不一致，特别是高并发时尤其明显
         */
        synchronized (ThreadByThread.class) {
            try {
                /**
                 * 每个线程都对用户放入账户余额做 扣钱 与 存钱操作
                 * 且扣钱、存钱次数相同、额度相同，所以无论多少个线程操作，账户余额都应该不变
                 */
                Random random = new Random();
                int ran = 0;
                for (int i = 0; i < 4; i++) {
                    /**每两次一个轮回做额度相同的存钱与扣钱操作*/
                    if (i % 2 == 0) {
                        ran = random.nextInt(8000);
                        user.setAccountBalance(user.getAccountBalance() - ran);
                        System.out.println(Thread.currentThread().getName() + " 0-> accountBalance = " + user.getAccountBalance() + " " + new Date());
                    } else {
                        user.setAccountBalance(user.getAccountBalance() + ran);
                        System.out.println(Thread.currentThread().getName() + " 1-> accountBalance = " + user.getAccountBalance() + " " + new Date());
                    }
                    TimeUnit.SECONDS.sleep(1 + new Random().nextInt(2));
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        /**采用线程池*/
        ExecutorService executorService = Executors.newCachedThreadPool();
        /**创建需要在各个线程之间共享的数据对象*/
        User user = new User();
        user.setAccountBalance(10000);
        for (int i = 0; i < 3; i++) {
            executorService.execute(new ThreadByThread(user));
            TimeUnit.SECONDS.sleep(1 + new Random().nextInt(2));
        }
    }
}